use std::{fmt};
use std::fmt::Formatter;
use std::str::FromStr;
use clap::Parser;
use crate::{CmdExector, process_csv};
use super::verify_input_file;


#[derive(Debug, Copy, Clone)]
pub enum OutputFormat {
    Json,
    Yaml,
    Toml,
}

impl CmdExector for CsvOpts {
    async fn execute(self) -> anyhow::Result<()> {
        let output = if let Some(output) = &self.output {
            output.clone()
        } else {
            format!("output.{}", self.format)
        };
        process_csv(&self.input, output, self.format)
    }
}

#[derive(Debug, Parser)]
pub struct CsvOpts {
    #[arg(short, long, value_parser = verify_input_file)]
    pub input: String,

    #[arg(short, long)]
    pub output: Option<String>,

    #[arg(short, long, default_value = "json")]
    pub format: OutputFormat,

    #[arg(short, long, default_value_t = ',')]
    pub delimiter: char,

    #[arg(long, default_value_t = true)]
    pub header: bool,
}


// fn verify_format(format:&str) -> Result<OutputFormat, anyhow::Error> {
//    format.parse::<OutputFormat>()
// }

impl From<OutputFormat> for &'static str {
    fn from(value: OutputFormat) -> Self {
        match value {
            OutputFormat::Yaml => "yaml",
            OutputFormat::Json => "json",
            OutputFormat::Toml => "toml",
        }
    }
}

impl FromStr for OutputFormat {
    type Err = anyhow::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            "json" => Ok(OutputFormat::Json),
            "yaml" => Ok(OutputFormat::Yaml),
            "toml" => Ok(OutputFormat::Toml),
            _ => Err(anyhow::anyhow!("Invalid format")),
        }
    }
}

impl fmt::Display for OutputFormat {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        // match self {
        //      OutputFormat::Json =>  write!(f,"{}","json"),
        //      OutputFormat::Yaml => write!(f,"{}","yaml"),
        //      OutputFormat::Toml => write!(f,"{}","toml"),
        //      _ => write!(f,"{}","json"),
        //  }
        write!(f, "{}", Into::<&str>::into(*self))
    }
}

